<?php
namespace App\Component\Payment;

use App\Core\Exception\DefaultException;
use App\Model\Account\CollectionAccountModel;
use EasySwoole\Component\Singleton;

class AlipayApp
{

    use Singleton;

    private $app_id; //支付宝应用ID
    private $notify_url; //回调地址
    private $public_key; //支付宝公钥
    private $private_key; //应用私钥
    private $gate_way; //请求网关

    public function __construct(){

    }

    /**
     * 支付方式配置信息 paymentConfig
     * @param int $id 支付方式ID
     * @return void
     */
    private function paymentConfig(int $id, string $gate_way = null){
        $payment = CollectionAccountModel::getOne(['id' => $id, 'state' => 1, 'channel' => 1]);
        if(empty($payment->id)) {
            throw new DefaultException('支付方式错误');
        }

        $this->app_id = $payment->app_id;
        $this->notify_url = $payment->notify_url;
        $this->public_key = $payment->public_key;
        $this->private_key = $payment->private_key;

        if(empty($gate_way)){
            if(\EasySwoole\EasySwoole\Config::getInstance()->getConf('ENV') == 'dev'){
                $this->gate_way = \EasySwoole\Pay\AliPay\GateWay::SANDBOX;
            }else{
                $this->gate_way = \EasySwoole\Pay\AliPay\GateWay::NORMAL;
            }
        }else{
            $this->gate_way = $gate_way;
        }
    }

    /**
     * 支付宝支付 pay
     * @param int $payment_id 支付方式ID
     * @param string $order_id 订单号
     * @param float $total_amount 支付金额
     * @param string $subject 主题
     * @return string
     * @throws DefaultException
     * @throws \EasySwoole\Pay\Exceptions\InvalidConfigException
     */
    public function pay(int $payment_id, string $order_id, float $total_amount, string $subject, string $gate_way = null){
        $this->paymentConfig($payment_id, $gate_way);

        // 设置支付配置
        $aliConfig = new \EasySwoole\Pay\AliPay\Config();
        ### 配置支付公共请求参数
        // (必须)设置 支付宝分配给开发者的应用ID
        $aliConfig->setAppId($this->app_id);
        // (必须)设置 请求网关(默认为 沙箱模式)
        $aliConfig->setGateWay($this->gate_way);

        // 设置 商户生成签名字符串所使用的签名算法类型，目前支持 RSA2 和 RSA，推荐使用 RSA2(默认为 'RSA2')
        $aliConfig->setSignType('RSA2');

        // 设置 支付宝服务器主动通知商户服务器里指定的页面http/https路径，即支付回调地址(默认为 null，可选参数)
        $aliConfig->setNotifyUrl($this->notify_url);

        // 设置 阿里应用公钥(支持 .pem 结尾的格式，默认为 PKCS1 格式)，用于支付回调时验证签名
        $aliConfig->setPublicKey($this->public_key); // 示例应用公钥字符串
        // 设置 阿里应用私钥(支持 .pem 结尾的格式，默认为 PKCS1 格式)，用于生成签名
        $aliConfig->setPrivateKey($this->private_key); // 示例应用私钥

        $pay = new \EasySwoole\Pay\Pay();

        ## (面向对象风格)设置请求参数 biz_content，组件自动帮你组装成对应的格式
        $order = new \EasySwoole\Pay\AliPay\RequestBean\App();
        // (必须)设置 订单总金额
        $order->setTotalAmount($total_amount); // 示例订单总金额，单位：元(仅供参考)
        // (必须)设置 商品标题/交易标题/订单标题/订单关键字等。注意：不可使用特殊字符，如 /，=，& 等。
        $order->setSubject($subject); // 示例商品标题(仅供参考)
        // (必须)设置 商户订单号(商户订单号。64 个字符以内的大小，仅支持字母、数字、下划线。需保证该参数在商户端不重复。)
        $order->setOutTradeNo($order_id); // 示例订单号(仅供参考)

        // 获取构造请求参数对象
        $res = $pay->aliPay($aliConfig)->app($order);
        // 拼接请求参数
        $aliUrlArr = [];
        foreach ($res->toArray() as $key => $val){
            $aliUrlArr[] = $key . "=" . urlencode($val);
        }
        return implode('&', $aliUrlArr);
    }

    public function verify(int $payment_id, array $param, string $gate_way = null){
        $this->paymentConfig($payment_id, $gate_way);
        $aliConfig = new \EasySwoole\Pay\AliPay\Config();
        $aliConfig->setGateWay($this->gate_way);
        $aliConfig->setAppId($this->app_id);
        $aliConfig->setPublicKey($this->public_key);
        $aliConfig->setPrivateKey($this->private_key);
        $pay = new \EasySwoole\Pay\Pay();

        unset($param['sign_type']);//需要忽略sign_type组装
        $order = new \EasySwoole\Pay\AliPay\RequestBean\NotifyRequest($param,true);
        $aliPay = $pay->aliPay($aliConfig);
        return $aliPay->verify($order);
    }
}
